package com.minelx.datamicroscope.querylanguage.data.sql;

import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.minelx.datamicroscope.querylanguage.data.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.unmodifiableList;

public class AliasedTablesBuilder {

	private final Map<CollectingKey, String> howMapping;

	private final Map<String, CollectingKey> aliasesToTableKeyMapping;

	private final List<CollectingKey> orderedTableKeys;

	private final List<TableAliasedSelectItem> joiningCollect;

	private final ColumnNames columnNames;

	public AliasedTablesBuilder(ColumnNames columnNames) {
		this.columnNames = columnNames;
		aliasesToTableKeyMapping = new HashMap<>();
		orderedTableKeys = new ArrayList<>();
		joiningCollect = new ArrayList<>();
		howMapping = new HashMap<>();
	}

	// FIXME 2022/3/10 needed test cover.
	public String addJoiningCollect(String selectItemKey) {
		if (columnNames.checkExistence(selectItemKey)) {
			return columnNames.joiningObtain(selectItemKey);
		}
		// create new joining column
		return addJoiningCollect0(selectItemKey);
	}

	private String addJoiningCollect0(String selectItemKey) {
		String[] pattern = selectItemKey.split("\\.");
		if (pattern.length != 2) {
			throw new DMSQLSyntaxException("select item key: " + selectItemKey + " has no table alias specified.");
		}
		String tableAlias = pattern[0];
		String fieldName = pattern[1];
		String resourceName = columnNames.joiningObtain(selectItemKey);
		CollectingKey collectingKeyOfAliasedTable = aliasesToTableKeyMapping.get(tableAlias);
		CollectingField collectingField = CollectingField.create(resourceName, fieldName, null);
		joiningCollect.add(TableAliasedSelectItem.create(
				tableAlias,
				new SelectItem(collectingKeyOfAliasedTable, collectingField)));
		return resourceName;
	}

	public void markAliasedTable(String alias, CollectingKey tableKey, String joiningMethod) {
		if (!orderedTableKeys.contains(tableKey)) {
			orderedTableKeys.add(tableKey);
		}
		aliasesToTableKeyMapping.put(alias, tableKey);
		// mark joining method to how mapping
		howMapping.put(tableKey, joiningMethod);
	}

	public AliasedTables build() {
		return new AliasedTables(aliasesToTableKeyMapping, joiningCollect, orderedTableKeys, howMapping);
	}

	List<TableAliasedSelectItem> joiningCollect() {
		return joiningCollect;
	}

	List<CollectingKey> tableKeys() {
		return unmodifiableList(orderedTableKeys);
	}

	public static AliasedTables createAliasedTables(SQLSelectQueryBlock firstQueryBlock, ColumnNames columnNames) {
		AliasedTablesBuilder result = new AliasedTablesBuilder(columnNames);
		AliasedTablesFulfil.create(firstQueryBlock.getFrom(), firstQueryBlock).fulfil(result);
		return result.build();
	}
}
